package castlewarserver;

import gameObjects.Castle;
import gameObjects.Cavalry;
import gameObjects.GameObject;
import gameObjects.Infantry;
import gameObjects.Pikeman;
import gameObjects.Unit;

import java.util.ArrayList;
import java.util.Collections;

import upgrades.CavalryUpgrade;
import upgrades.HealCastle;
import upgrades.InfantryUpgrade;
import upgrades.PikemanUpgrade;
import upgrades.Upgrade;

public class Game {
	private ArrayList<Unit> units =  new ArrayList<Unit>();
	private Castle castleOrange;
	private Castle castleBlue;

	private GameParams gameParams;

	public Game(){

		init();
	}

	private void init(){
		gameParams = XmlSerializer.deserializeGameParams(Messages.getString("Game.paramsFile")); //$NON-NLS-1$
	}

	public String newGame(String player){
		String result = "";

		if (gameParams.isBluePresent() && gameParams.isOrangePresent()){
			result ="BOTH";
		}
		else if ( !gameParams.isOrangePresent() && player.equalsIgnoreCase("ORANGE")){
			result = "ORANGE";
			gameParams.setOrangePresent(true);
		}

		else if ( !gameParams.isBluePresent() && player.equalsIgnoreCase("BLUE")){
			result = "BLUE"; 
			gameParams.setBluePresent(true);
		}


		XmlSerializer.serializeGameParams(gameParams, Messages.getString("Game.paramsFile"));
		return result;
	}

	public void resetGame(){
		GameParams params = new GameParams();
		params.setObjCounter(0);
		XmlSerializer.serializeGameParams(params, Messages.getString("Game.paramsFile")); //$NON-NLS-1$


		castleOrange = new Castle(Messages.getString("Game.Orange")); //$NON-NLS-1$
		castleOrange.setX(26);
		castleOrange.setY(1);

		castleBlue = new Castle(Messages.getString("Game.Blue")); //$NON-NLS-1$
		castleBlue.setX(25);
		castleBlue.setY(27);

		units= new ArrayList<Unit>();
		Infantry infantryBlue1 = new Infantry(Messages.getString("Game.Blue")); //$NON-NLS-1$
		infantryBlue1.setX(23);
		infantryBlue1.setY(27);
		units.add(infantryBlue1);

		Infantry infantryOrange1 = new Infantry(Messages.getString("Game.Orange")); //$NON-NLS-1$
		infantryOrange1.setX(25);
		infantryOrange1.setY(2);
		units.add(infantryOrange1);

	
		ArrayList<Upgrade> upgradesOrange = new ArrayList<Upgrade>();
		upgradesOrange.add(new InfantryUpgrade());
		upgradesOrange.add(new PikemanUpgrade());
		upgradesOrange.add(new CavalryUpgrade());
		upgradesOrange.add(new HealCastle());


		ArrayList<Upgrade> upgradesBlue = new ArrayList<Upgrade>();
		upgradesBlue.add(new InfantryUpgrade());
		upgradesBlue.add(new PikemanUpgrade());
		upgradesBlue.add(new CavalryUpgrade());
		upgradesBlue.add(new HealCastle());;

		XmlSerializer.serializeUpgrades(upgradesOrange, "upgradesOrange.xml");
		XmlSerializer.serializeUpgrades(upgradesBlue, "upgradesBlue.xml");

		XmlSerializer.serializeUnits(units, Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		XmlSerializer.serializeCastle(castleBlue, Messages.getString("Game.castleBlueFile")); //$NON-NLS-1$
		XmlSerializer.serializeCastle(castleOrange, Messages.getString("Game.castleOrangeFile")); //$NON-NLS-1$
	}

	public boolean isPlayerTaken(String player){
		if (player.equalsIgnoreCase("BLUE")){
			return gameParams.isBluePresent();
		}
		else{
			return gameParams.isOrangePresent();
		}
	}

	public Unit getUnitAt(int index){
		units=XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		return units.get(index);
	}

	public Unit[] getAllUnits (){
		units=XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		Unit[] unitsTab = new Unit[units.size()];
		for (int i = 0; i< unitsTab.length; i++){
			unitsTab[i]= units.get(i);
		}

		return unitsTab ;
	}

	public Unit moveUnit(Unit unit,int x, int y){

		units=XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$

		unit = findUnit(unit);
		unit.setX(x);
		unit.setY(y);
		unit.setChanged(true);

		XmlSerializer.serializeUnits(units, Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		return unit;

	}

	public Unit[] attackUnit(Unit attacker, Unit defender ){
		units=XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$

		attacker = findUnit(attacker);
		defender = findUnit(defender);

		moveToAttack(attacker, defender);

		defender.setHp(defender.getHp()- attacker.getDamage());
		attacker.setChanged(true);
		if (defender.getHp() <= 0){
			units.remove(defender);
			// get gold 
			Castle castle;
			if (attacker.getPlayer().equalsIgnoreCase("ORANGE")){
				castle = getCastleOrange();
				castle.setGold(castle.getGold() + defender.getGold());
				XmlSerializer.serializeCastle(castle, Messages.getString("Game.castleOrangeFile"));
			}
			else{
				castle = getCastleBlue();
				castle.setGold(castle.getGold() + defender.getGold());
				XmlSerializer.serializeCastle(castle, Messages.getString("Game.castleBlueFile"));
			}
		}

		Unit[] pair =new Unit[] {attacker,defender};

		XmlSerializer.serializeUnits(units, Messages.getString("Game.unitsFile")); //$NON-NLS-1$

		return pair;
	}

	public Unit attackCastle (Unit unit){
		Castle castle;
		String file;
		units= XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		unit = findUnit(unit);

		if (unit.getPlayer().equalsIgnoreCase(Messages.getString("Game.Orange"))){ //$NON-NLS-1$
			file=Messages.getString("Game.castleBlueFile"); //$NON-NLS-1$
		}
		else{
			file=Messages.getString("Game.castleOrangeFile"); //$NON-NLS-1$
		}
		castle = XmlSerializer.deserializeCastle(file);

		moveToAttack(unit, castle);

		castle.setHp(castle.getHp() - unit.getDamage());

		unit.setChanged(true);

		if (castle.getHp() <= 0){
			endGame();
		}

		XmlSerializer.serializeUnits(units, Messages.getString("Game.unitsFile")); //$NON-NLS-1$
		XmlSerializer.serializeCastle(castle, file);
		return unit;
	}
	public Unit buyUnit(String unitType,String player){

		String file;
		if (player.equalsIgnoreCase(Messages.getString("Game.Orange"))){ //$NON-NLS-1$
			file= Messages.getString("Game.castleOrangeFile"); //$NON-NLS-1$
		}
		else{
			file = Messages.getString("Game.castleBlueFile"); //$NON-NLS-1$
		}
		Castle castle = XmlSerializer.deserializeCastle(file);

		Unit unit = null;
		units = XmlSerializer.deserializeUnits(Messages.getString("Game.unitsFile")); //$NON-NLS-1$

		int goldAfter = castle.getGold();
		if (unitType.equalsIgnoreCase("infantry")){ //$NON-NLS-1$

			goldAfter -= castle.getInfantryPrice();

			if( goldAfter >= 0 ){
				unit = new Infantry(player);
			}
		}
		else if (unitType.equalsIgnoreCase("pikeman")){ //$NON-NLS-1$
			goldAfter -= castle.getPikemanPrice();

			if( goldAfter >= 0 ){
				unit = new Pikeman(player);
			}
		}
		else{
			goldAfter -= castle.getCavalryPrice();

			if( goldAfter >= 0 ){
				unit = new Cavalry(player);
			}
		}

		if (unit != null){

			unit.setX(castle.getX());
			unit.setY(castle.getY() +1);
			units.add(unit);

			castle.setGold(goldAfter);

			XmlSerializer.serializeUnits(units, Messages.getString("Game.unitsFile")); //$NON-NLS-1$
			XmlSerializer.serializeCastle(castle, file);
		}

		return unit;

	}

	private void endGame(){
		gameParams.setGameEnd(true);
		XmlSerializer.serializeGameParams(gameParams, "gameparams.xml");
	}

	public boolean isEndOfGame(){
		return gameParams.isGameEnd();
	}
	private void  moveToAttack(GameObject attacker, GameObject defender){

		int diffX = defender.getX() - attacker.getX();
		int diffY = defender.getY() - attacker.getY();
		int absDiffX = Math.abs(diffX);
		int absDiffY = Math.abs(diffY);

		if ( absDiffX > absDiffY ){
			if( diffX < 0 ){
				attacker.setX(defender.getX() + 1);
			}
			else{
				attacker.setX(defender.getX() - 1);
			}
		}
		else{
			if( diffY < 0 ){
				attacker.setY(defender.getY() + 1);
			}
			else{
				attacker.setY(defender.getY() - 1);
			}
		}
	}

	public void endTurn(String player){

		if (gameParams.getActualPlayer().equalsIgnoreCase("ORANGE")){
			gameParams.setActualPlayer("BLUE");
		}
		else{
			gameParams.setActualPlayer("ORANGE");
		}

		units = XmlSerializer.deserializeUnits("units.xml");

		for (Unit unit:units){
			unit.setChanged(false);
		}

		XmlSerializer.serializeUnits(units, "units.xml");
		XmlSerializer.serializeGameParams(gameParams, Messages.getString("Game.paramsFile"));
	}

	public synchronized String getActualPlayer(){
		return gameParams.getActualPlayer();
	}

	public Castle getCastleOrange() {
		return XmlSerializer.deserializeCastle(Messages.getString("Game.castleOrangeFile")); //$NON-NLS-1$
	}

	public Castle getCastleBlue() {

		return XmlSerializer.deserializeCastle(Messages.getString("Game.castleBlueFile")); //$NON-NLS-1$
	}

	public Upgrade[] getUpgrades(String player){
		ArrayList <Upgrade> upgrades = null;

		if(player.equalsIgnoreCase("ORANGE")){
			upgrades = XmlSerializer.deserializeUpgrades("upgradesOrange.xml");	
		}
		else{
			upgrades = XmlSerializer.deserializeUpgrades("upgradesBlue.xml");
		}

		Upgrade[] upgradeTab= new Upgrade[upgrades.size()];

		for (int i = 0; i< upgrades.size() ; i++){
			upgradeTab[i] = upgrades.get(i);
		}
		return upgradeTab;
	}

	public boolean buyUpgrade (String player, int index){

		ArrayList <Upgrade> upgrades = null;
		Castle castle;
		String castleFile;
		String upgradesFile;

		if(player.equalsIgnoreCase("ORANGE")){
			upgrades = XmlSerializer.deserializeUpgrades("upgradesOrange.xml");	
			upgradesFile="upgradesOrange.xml";
			castle = getCastleOrange();
			castleFile= "castleOrange.xml";
		}
		else{
			upgrades = XmlSerializer.deserializeUpgrades("upgradesBlue.xml");
			upgradesFile="upgradesBlue.xml";
			castle = getCastleBlue();
			castleFile= "castleBlue.xml";
		}

		Upgrade upgrade = getConcreteUpgrade(index, upgrades);
		int goldAfter = castle.getGold() - upgrade.getPrice();

		if (goldAfter < 0){
			return false;
		}

		upgrade.action(castle);

		castle.setGold(goldAfter);

		if ( upgrade.isToRemove() ){
			upgrades.remove(index);
		}

		XmlSerializer.serializeCastle(castle, castleFile);
		XmlSerializer.serializeUpgrades(upgrades, upgradesFile);

		return true;

	}

	private Upgrade getConcreteUpgrade(int index, ArrayList<Upgrade> upgrades ){
		Upgrade upgrade = upgrades.get(index);

		if (upgrade.getName().equalsIgnoreCase("Infantry upgrade") ){
			upgrade = new InfantryUpgrade();
		}

		if (upgrade.getName().equalsIgnoreCase("Pikeman upgrade") ){
			upgrade = new PikemanUpgrade();
		}

		if (upgrade.getName().equalsIgnoreCase("Cavalry upgrade") ){
			upgrade = new CavalryUpgrade();
		}

		if (upgrade.getName().equalsIgnoreCase("Heal castle") ){
			upgrade = new HealCastle();
		}

		return upgrade;
	}

	private Unit findUnit(Unit unit){
		return units.get(Collections.binarySearch(units,unit));
	}

	public String info(){
		return "Castle War Server v1.0"; //$NON-NLS-1$
	}


}
